#include <sys/time.h>
#include <signal.h>
#include <sys/select.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/input.h>

#include <iostream>
#include <vector>

#include "timer.h"
#include "singleton.h"
#include "smart_pointer.h"


#define TIMER_RESOLUTION        1000
#define set_nonblock(fd)        \
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)

namespace kbdenhance {
e7::common::singleton_mng g_singleton_mng;
}

using e7::common::array;
using e7::common::smart_pointer;
using e7::common::raii;
using e7::common::fdraii;
using kbdenhance::timer_heap;

using kbdenhance::g_singleton_mng;
using kbdenhance::g_now;
using kbdenhance::g_timer_heap;


static int _reportkey(int fd, uint16_t type, uint16_t keycode, int32_t value)
{
    struct input_event event;

    event.type = type;
    event.code = keycode;
    event.value = value;

    ::gettimeofday(&event.time, 0);

    if (-1 == ::write(fd, &event, sizeof(struct input_event))) {
        return -1;
    }

    return 0;
}
static void reportkey(int fd, uint16_t type, uint16_t keycode, int32_t value)
{
    (void)::_reportkey(fd, EV_MSC, MSC_SCAN, keycode);
    (void)::_reportkey(fd, EV_KEY, keycode, value);
    (void)::_reportkey(fd, EV_SYN, SYN_REPORT, 0);
    return;
}


namespace test {
class hello_on_timeout : public kbdenhance::i_on_timeout
{
public:
    virtual void do_trigger(void)
    {
        timer_heap *th = g_timer_heap;

        struct tm tmp_tm;
        time_t tmp_now = g_now / 1000;
        ::gmtime_r(&tmp_now, &tmp_tm);
        ::fprintf(
            stderr, "\r%lu -- %d.%02d.%02d %02d:%02d:%02d",
            tmp_now, tmp_tm.tm_year + 1900, 1 + tmp_tm.tm_mon, tmp_tm.tm_mday,
            tmp_tm.tm_hour + 8, tmp_tm.tm_min, tmp_tm.tm_sec
        );

        th->heap.push(
            new kbdenhance::timer(g_now + 1000, new hello_on_timeout)
        );
    }
};
}
using test::hello_on_timeout;


namespace kbdenhance {
// 按键动作超时回调
static int const KEY_RELESS = 0;
static int const KEY_PRESS = 1;
static int const KEY_HOLDON= 2;
template <int actype>
class keyaction : public i_on_timeout
{
public:
    explicit keyaction(int fd) : kbdfd(fd) {}
    virtual ~keyaction(void) {}

    virtual void do_trigger(void)
    {
        ::reportkey(kbdfd, EV_KEY, KEY_A, actype);
    }

private:
    int kbdfd;
};
}


namespace kbdenhance {
static void sigalrm_handler(int signum)
{
    static_cast<void>(::__sync_add_and_fetch (&g_now, 1));

    return;
}


static int init_signal(void)
{
    struct sigaction sa;

    sa.sa_flags = 0;
    sa.sa_handler = sigalrm_handler;   //信号处理函数

    if (-1 == ::sigaction(SIGALRM, &sa, NULL)) {
        return -1;
    }

    return 0;
}


int main(int argc, char *argv[], char *env[])
{
    int rslt;
    struct timeval tv;
    struct itimerval itm;
    timer_heap *th = g_timer_heap;

    if (argc < 2) {
        fprintf(stderr, "usage: %s device\n", argv[0]);
        return EXIT_FAILURE;
    }

    // 初始化信号
    if (-1 == init_signal()) {
        return EXIT_FAILURE;
    }

    // 打开键盘设备
    int kbdfd = ::open(argv[1], O_WRONLY | O_NONBLOCK);
    if (-1 == kbdfd) {
        fprintf(stderr, "open device %s failed:%s\n", argv[1], strerror(errno));
        return EXIT_FAILURE;
    }
    fdraii autoclose_kbdfd(kbdfd);

    // 初始化定时器
    itm.it_interval = (struct timeval){0, TIMER_RESOLUTION};
    itm.it_value = (struct timeval){0, 20 * 1000};
    rslt = ::setitimer(ITIMER_REAL, &itm, NULL);
    if (-1 == rslt) {
        return EXIT_FAILURE;
    }

    rslt = ::gettimeofday(&tv, NULL);
    if (-1 == rslt) {
        return EXIT_FAILURE;
    }
    g_now = tv.tv_sec * 1000 + tv.tv_usec / 1000;

    // 初始化udp监听
    int usock = ::socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == rslt) {
        return EXIT_FAILURE;
    }
    fdraii autoclose_usock(usock);
    set_nonblock(usock);

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9797);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (-1 == ::bind(usock, (struct sockaddr *)&addr, sizeof(addr))) {
        return EXIT_FAILURE;
    }

    // 时钟驱动循环
    int capture_count = 0;
    std::vector<uint8_t> rbuf;

    rbuf.assign(480, 0);
    while (true) {
        fd_set rfd;

        FD_ZERO(&rfd);
        FD_SET(usock, &rfd);
        rslt = ::select(usock + 1, &rfd, NULL, NULL, NULL);

        if ((-1 == rslt) && (EINTR != errno)) {
            break;
        }

        ssize_t rcvsz = ::recvfrom(usock, rbuf.data(), 480, 0, NULL, NULL);
        if (-1 == rcvsz > 0) {
            rbuf[rcvsz] = 0;
            fprintf(stderr, "%.*s\n", rcvsz, rbuf.data());
        }

        while (! th->heap.empty()) {
            kbdenhance::timer *top = th->heap.top();

            if (top->timeout > g_now) { // 无超时
                break;
            }

            smart_pointer<kbdenhance::timer> auto_free_kt(top);
            top->trigger->do_trigger();
            th->heap.pop();
        }

        kbdenhance::timer *kt;
        if (th->heap.empty()) {
            kt = new kbdenhance::timer(g_now, new keyaction<KEY_PRESS>(kbdfd));
            th->heap.push(kt);
            kt = new kbdenhance::timer(g_now + 20, new keyaction<KEY_RELESS>(kbdfd));
            th->heap.push(kt);
        }
    }

    return EXIT_SUCCESS;
}
}


int main(int argc, char *argv[], char *env[])
{
    int rslt = 0;

    // 初始化全局单例
    g_timer_heap = new timer_heap;
    g_singleton_mng.append("kbdenhance::timer_heap", g_timer_heap);

    rslt = kbdenhance::main(argc, argv, env);

    return rslt;
}
